﻿/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../data_struct/head.h"
#include "../macro/head.h"
#include "ssl_impl.h"
#include "rsa_impl.h"
#include "des_impl.h"
#include "hook.h"
#include "mgr.h"

namespace xos_encrypt
{

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    static xos_container::i_container * container_ptr = 0;
    static mgr * package_mgr_ptr = 0;

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    mgr::mgr()
    {
        init_data();
    }

    mgr::~mgr()
    {}

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int mgr::static_init( xos_container::i_container * pContainer, i_encrypt_mgr ** ppv )
    {
        int ret = 0;

        mgr::T * pObj = 0;

        if( ( 0 == ret ) && package_mgr_ptr )
        {
            ret = 1;
        }

        if( 0 == ret )
        {
            container_ptr = pContainer;
        }

        if( 0 == ret )
        {
            pObj = new mgr::T;
            if( pObj )
            {
                package_mgr_ptr = pObj;
            }
            else
            {
                ret = 1;
            }
        }

        if( 0 == ret )
        {
            ret = pObj->init();
            if( 0 != ret )
            {
                ret = 1;
            }
        }

        if( 0 != ret )
        {
            package_mgr_ptr = 0;
        }
        else
        {
            *ppv = pObj;
            pObj = 0;
        }

        xos_stl::release_interface( pObj );

        return ret;
    }

    xos_container::i_container * mgr::container()
    {
        return container_ptr;
    }

    xos_common::i_common * mgr::common()
    {
        return container()->common();
    }

    xos_log::i_log * mgr::log()
    {
        return container()->log();
    }

    xos::i_misc * mgr::misc()
    {
        return container()->misc();
    }

    xos::i_crt * mgr::crt()
    {
        return container()->crt();
    }

    xos_box::i_big_buf * mgr::big_buf()
    {
        return container()->big_buf();
    }

    xos_box::i_buf * mgr::buf()
    {
        return container()->buf();
    }

    xos::i_xos * mgr::xos()
    {
        return container()->xos();
    }

    mgr * mgr::get()
    {
        return package_mgr_ptr;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int mgr::create( enumInterfaceType eType, void ** ppv )
    {
        int ret = 0;

        xos::i_release * pRet = 0;

        switch( eType )
        {
        case enumInterfaceType::SSL:
            {
                ssl_impl::T * pT = ssl_impl::get_item_from_pool( true );
                pT->init();
                pRet = pT;
            }
            break;
        case enumInterfaceType::RSA:
            {
                rsa_impl::T * pT = rsa_impl::get_item_from_pool( true );
                pT->init();
                pRet = pT;
            }
            break;
        default:
        case enumInterfaceType::DES:
            {
                des_impl::T * pT = des_impl::get_item_from_pool( true );
                pT->init();
                pRet = pT;
            }
            break;
            {
                ret = 1;
            }
        }

        if( 0 != ret )
        {
            xos_stl::release_interface( pRet );
        }
        else
        {
            *ppv = pRet;
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int mgr::set_ssl_server_cert( const char * lpszFile )
    {
        int ret = 0;
        m_server_cert = lpszFile;
        return ret;
    }

    int mgr::set_ssl_server_key( const char * lpszFile )
    {
        int ret = 0;
        m_server_key = lpszFile;
        return ret;
    }

    int mgr::set_ssl_client_cert( const char * lpszFile )
    {
        int ret = 0;
        m_client_cert = lpszFile;
        return ret;
    }

    int mgr::set_ssl_client_key( const char * lpszFile )
    {
        int ret = 0;
        m_client_key = lpszFile;
        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    // rsa方法
    int mgr::set_rsa_private_key( const char * lpszFile )
    {
        int ret = 0;
        m_private_key_file = lpszFile;
        return ret;
    }

    int mgr::set_rsa_public_key( const char * lpszFile )
    {
        int ret = 0;
        m_public_key_file = lpszFile;
        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int mgr::init_ssl()
    {
        int ret = 0;

        if( 0 == ret )
        {
            ret = init_ssl_server();
        }

        if( 0 == ret )
        {
            ret = init_ssl_client();
        }

        return ret;
    }

    int mgr::term_ssl()
    {
        int ret = 0;

        if( m_pClientCtx )
        {
            SSL_CTX_free( ( SSL_CTX * )m_pClientCtx );
            m_pClientCtx = 0;
        }

        if( m_pServerCtx )
        {
            SSL_CTX_free( ( SSL_CTX * )m_pServerCtx );
            m_pServerCtx = 0;
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    /*
        1024 ->密文长度 128-11 ，明文128
        2048 ->密文长度 256 ，明文256
        4096 ->密文长度 512 ，明文512
    */
    int mgr::init_rsa()
    {
        int ret = 0;

        if( ( 0 == ret ) && !m_private_key_file.empty() )
        {
            RSA * pRSA = 0;
            BIO * pBIO = 0;
            pBIO = BIO_new_file( m_private_key_file.c_str(), "rb" );
            if( pBIO )
            {
                pRSA = PEM_read_bio_RSAPrivateKey( pBIO, NULL, NULL, NULL );
                if( !pRSA )
                {
                    ret = 1;
                }
            }
            else
            {
                ret = 1;
            }
            if( 0 == ret )
            {
                m_nRsaLen = RSA_size( pRSA );
                m_pPrivateRSA = pRSA;
            }
            if( pBIO )
            {
                BIO_free( pBIO );
                pBIO = 0;
            }
        }

        if( ( 0 == ret ) && !m_public_key_file.empty() )
        {
            RSA * pRSA = 0;
            BIO * pBIO = 0;
            pBIO = BIO_new_file( m_public_key_file.c_str(), "rb" );
            if( pBIO )
            {
                pRSA = PEM_read_bio_RSA_PUBKEY( pBIO, NULL, NULL, NULL );
                if( !pRSA )
                {
                    ret = 1;
                }
            }
            else
            {
                ret = 1;
            }
            if( 0 == ret )
            {
                m_nRsaLen = RSA_size( pRSA );
                m_pPublicRSA = pRSA;
            }
            if( pBIO )
            {
                BIO_free( pBIO );
                pBIO = 0;
            }
        }

        return ret;
    }

    int mgr::term_rsa()
    {
        int ret = 0;

        if( m_pPrivateRSA )
        {
            RSA_free( ( RSA * )m_pPrivateRSA );
            m_pPrivateRSA = 0;
        }

        if( m_pPublicRSA )
        {
            RSA_free( ( RSA * )m_pPublicRSA );
            m_pPublicRSA = 0;
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int mgr::put_back_to_pool( T * pT, bool bLock )
    {
        int ret = 0;
        delete this;
        return ret;
    }

    int mgr::init_ssl_server()
    {
        int ret = 0;

        SSL_CTX * pCtx = 0;

        if( 0 == ret )
        {
            pCtx = SSL_CTX_new( SSLv23_server_method() );
            if( !pCtx )
            {
                ret = 1;
            }
        }

        if( ( 0 == ret ) && !m_server_cert.empty() )
        {
            int r = SSL_CTX_use_certificate_file( pCtx, m_server_cert.c_str(), SSL_FILETYPE_PEM );
            if( r <= 0 )
            {
                ret = 1;
            }
        }

        if( ( 0 == ret ) && !m_server_key.empty() )
        {
            int r = SSL_CTX_use_PrivateKey_file( pCtx, m_server_key.c_str(), SSL_FILETYPE_PEM );
            if( r <= 0 )
            {
                ret = 1;
            }
        }

        if( ( 0 == ret ) && !m_server_key.empty() )
        {
            int r = SSL_CTX_check_private_key( pCtx );
            if( r <= 0 )
            {
                ret = 1;
            }
        }

        if( 0 == ret )
        {
            m_pServerCtx = pCtx;
        }
        else
        {
            SSL_CTX_free( pCtx );
        }

        return ret;
    }

    int mgr::init_ssl_client()
    {
        int ret = 0;

        SSL_CTX * pCtx = 0;

        if( 0 == ret )
        {
            pCtx = SSL_CTX_new( SSLv23_client_method() );
            if( !pCtx )
            {
                ret = 1;
            }
        }

        if( ( 0 == ret ) && !m_client_cert.empty() )
        {
            int r = SSL_CTX_use_certificate_file( pCtx, m_client_cert.c_str(), SSL_FILETYPE_PEM );
            if( r <= 0 )
            {
                ret = 1;
            }
        }

        if( ( 0 == ret ) && !m_client_key.empty() )
        {
            int r = SSL_CTX_use_PrivateKey_file( pCtx, m_client_key.c_str(), SSL_FILETYPE_PEM );
            if( r <= 0 )
            {
                ret = 1;
            }
        }

        if( ( 0 == ret ) && !m_client_key.empty() )
        {
            int r = SSL_CTX_check_private_key( pCtx );
            if( r <= 0 )
            {
                ret = 1;
            }
        }

        if( 0 == ret )
        {
            m_pClientCtx = pCtx;
        }
        else
        {
            SSL_CTX_free( pCtx );
        }

        return ret;
    }

    int mgr::init_data()
    {
        int ret = 0;

        m_pPrivateRSA = 0;
        m_pPublicRSA = 0;
        m_nRsaLen = 0;

        m_pClientCtx = 0;
        m_pServerCtx = 0;

        return ret;
    }

    int mgr::init()
    {
        int ret = 0;

        if( 0 == ret )
        {
            int r = OPENSSL_init_ssl( OPENSSL_INIT_LOAD_CONFIG, NULL );
            if( 0 == r )
            {
                LOG4( "openssl init failed" );
                ret = 1;
            }
            else
            {
                ERR_clear_error();
            }
        }

        if( 0 == ret )
        {
            log()->add_log_module( LOG_NAME, 1 );
            log()->add_log_module( LOG_NAME, 2 );
            log()->add_log_module( LOG_NAME, 3 );
            log()->add_log_module( LOG_NAME, 4 );
        }

        if( 0 == ret )
        {
            ret = hook::init();
        }

        return ret;
    }

    int mgr::term()
    {
        int ret = 0;

        {
            term_ssl();
            term_rsa();
        }

        {
            hook::term();
        }
        {
            package_mgr_ptr = 0;
            container_ptr = 0;
        }

        {
            EVP_cleanup();                 //For EVP
            CRYPTO_cleanup_all_ex_data();  //generic 
            ERR_free_strings();            //for ERR
        }

        return ret;
    }

} // xos_encrypt
